package com.ms.banner;

import com.ms.banner.holder.BannerViewHolder;
import com.ms.banner.listener.OnBannerClickListener;

import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.Image;
import ohos.agp.components.LayoutScatter;
import ohos.agp.components.PageSlider;
import ohos.agp.components.PageSliderProvider;
import ohos.agp.components.StackLayout;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.PixelMapElement;
import ohos.app.Context;
import ohos.eventhandler.EventRunner;
import ohos.global.resource.NotExistException;
import ohos.global.resource.Resource;
import ohos.global.resource.ResourceManager;
import ohos.global.resource.WrongTypeException;
import ohos.media.image.ImageSource;
import ohos.media.image.PixelMap;
import ohos.multimodalinput.event.TouchEvent;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import static ohos.multimodalinput.event.TouchEvent.CANCEL;
import static ohos.multimodalinput.event.TouchEvent.NONE;
import static ohos.multimodalinput.event.TouchEvent.PRIMARY_POINT_DOWN;
import static ohos.multimodalinput.event.TouchEvent.PRIMARY_POINT_UP;

/**
 * Banner
 *
 * @author name
 * @since 2021-03-20
 */
public class Banner extends StackLayout implements PageSlider.PageChangedListener {

    // 默认指示器数量
    private static final int INDICATORNUM = 0;

    // 默认当前目标
    private static final int CURRENTITEM = -1;

    // 默认当前页面
    private static final int CURRENTPAGE = 0;

    // 默认gravity
    private static final int GRAVITY = -1;

    // banner背景图片
    private Element bannerBackgroundImage;

    // banner风格
    private int bannerStyle = BannerConfig.CIRCLE_INDICATOR;

    // 延迟时间
    private int delayTime = BannerConfig.TIME;

    // 是否自动播放(默认设置为自动播放)
    private boolean isAutoPlay = BannerConfig.IS_AUTO_PLAY;

    // 是否启动(默认不启动)
//    private boolean isStart = false;

    // 是否准备好
//    private boolean isPrepare = false;

    // 是否滚动
    private boolean isScroll = BannerConfig.IS_SCROLL;

    // 是否循环
    private boolean isLoop = BannerConfig.IS_LOOP;

    // 数量(图片的数量)
    private int count = INDICATORNUM;

    // 当前目标
    private int currentItem = CURRENTITEM;

    // 当前页面
    private int mCurrentPage = CURRENTPAGE;

    // 重量
//    private int gravity = GRAVITY;

    // 图片地址列表
    private List mDatas;

    private BannerViewHolder creator;

    private List<Component> imageViews;

    // 上下文
    private Context context;

    private BannerViewPager viewPager;

    // banner默认图片
    private Image bannerDefaultImage;

    // 页面滑动适配器
    private BannerPagerAdapter adapter;

    // 页面改变监听器
    private PageSlider.PageChangedListener mOnPageChangeListener;

    // banner点击监听器
    private OnBannerClickListener listener;

    private EventRunner runner = EventRunner.current();

    private WeakHandler handler = new WeakHandler(runner);


    public PageSlider getSlider() {
        return viewPager;
    }

    /**
     * 单参构造
     *
     * @param context
     */
    public Banner(Context context) {
        this(context, null);
    }

    /**
     * 双参构造
     *
     * @param context
     * @param attrSet
     */
    public Banner(Context context, AttrSet attrSet) {
        this(context, attrSet, null);
    }

    /**
     * 全参构造
     *
     * @param context
     * @param attrSet
     * @param styleName
     */
    public Banner(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        this.context = context;
        mDatas = new ArrayList<>();
        imageViews = new ArrayList<>();
        init(context, attrSet);
    }

    /**
     * 初始化
     *
     * @param context 上下文对象
     * @param attrs   属性集
     */
    private void init(Context context, AttrSet attrs) {
        handleTypedArray(context, attrs);
        Component view = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_banner, this, true);
        bannerDefaultImage = (Image) view.findComponentById(ResourceTable.Id_bannerDefaultImage);
        viewPager = (BannerViewPager) view.findComponentById(ResourceTable.Id_bannerViewPager);
        viewPager.setCircularModeEnabled(true);
        bannerDefaultImage.setImageElement(bannerBackgroundImage);
    }

    private void handleTypedArray(Context context, AttrSet attrs) {
        if (attrs == null) {
            return;
        }
        delayTime = BannerConfig.TIME;
        isAutoPlay = BannerConfig.IS_AUTO_PLAY;
        isLoop = BannerConfig.IS_LOOP;

        try {
            bannerBackgroundImage =new PixelMapElement(Utils.getInstance()
                    .getPixelMapFromMedia(getContext(), BannerConfig.DEFAULT_IMAGE));
        } catch (NotExistException e) {
            Log.e("Banner", e.getMessage());
        } catch (WrongTypeException e) {
            Log.e("Banner", e.getMessage());
        } catch (IOException e) {
            Log.e("Banner", e.getMessage());
        }
    }

    /**
     * 设置是否自动播放
     *
     * @param isAutoPlay 自动播放
     * @return Banner
     */
    public Banner setAutoPlay(boolean isAutoPlay) {
        this.isAutoPlay = isAutoPlay;
        return this;
    }

    /**
     * 设置延迟时间
     *
     * @param delayTime 延迟时间
     * @return Banner
     */
    public Banner setDelayTime(int delayTime) {
        this.delayTime = delayTime;
        return this;
    }

    /**
     * 设置页面图片列表和
     *
     * @param datas   图片地址列表(网络图片或本地图片)
     * @param creator
     * @return Banner
     */
    public Banner setPages(List<?> datas, BannerViewHolder creator) {
        this.mDatas.clear();
        this.imageViews.clear();
        this.mDatas.addAll(datas);
        this.creator = creator;
        this.count = datas.size();
        try {
            this.setImageList(datas);
        } catch (NotExistException e) {
            Log.e("Banner", e.getMessage());
        } catch (WrongTypeException e) {
            Log.e("Banner", e.getMessage());
        } catch (IOException e) {
            Log.e("Banner", e.getMessage());
        }
        return this;
    }

    /**
     * 启动banner
     *
     * @return Banner
     */
    public Banner start() {
        if (count > 0) {
            // 隐藏默认图片
            bannerDefaultImage.setVisibility(HIDE);
            setData();
        } else {
            bannerDefaultImage.setVisibility(VISIBLE);
        }
//        isPrepare = true;
        return this;
    }

    // 设置图片list
    private void setImageList(List<?> imagesUrl) throws NotExistException, WrongTypeException, IOException {
        if (imagesUrl == null || imagesUrl.size() <= 0) {
            bannerDefaultImage.setVisibility(VISIBLE);
            Log.e("setImageList", "The image data set is empty.");
            return;
        }
        bannerDefaultImage.setVisibility(HIDE);
        Log.e("setImageList", "======================The image data set " + imagesUrl.size());
        for (int ic = 0; ic <= count + 1; ic++) {
            Log.e("setImageList", "======================The image data set " + ic);
            Object url = null;
            if (ic == 0) {
                url = imagesUrl.get(count - 1);
            } else if (ic == count + 1) {
                url = imagesUrl.get(0);
            } else {
                url = imagesUrl.get(ic - 1);
            }
            Image image1 = new Image(context);
            if (url instanceof String) {
                Utils.getInstance().setBitmap(context, image1, (String) url);
            } else {
                ImageSource.SourceOptions options = new ImageSource.SourceOptions();
                options.formatHint = "image/jpg";
                ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();
                ResourceManager manager = context.getResourceManager();
                String path = manager.getMediaPath((Integer) url);
                Log.e("setImageList", "======================The image data path is  " + path);
                Resource r1 = manager.getRawFileEntry(path).openRawFile();
                ImageSource source = ImageSource.create(r1, options);
                PixelMap p1 = source.createPixelmap(decodingOptions);
                image1.setPixelMap(p1);
            }
            imageViews.add(image1);
        }
    }

    private void setData() {
        if (isLoop) {
            if (mCurrentPage > 0 && mCurrentPage < count) {
                currentItem = 0;
            } else {
                currentItem = mCurrentPage;
            }
        } else {
            if (mCurrentPage > 0 && mCurrentPage < count) {
                currentItem = mCurrentPage;
            } else {
                currentItem = 0;
            }
        }
        if (adapter == null) {
            adapter = new BannerPagerAdapter();
            viewPager.addPageChangedListener(this);
            viewPager.setProvider(adapter);
        } else {
            adapter.notifyDataChanged();
        }
        viewPager.setFocusable(1);
        if (isScroll && count > 1) {
            viewPager.setScrollable(true);
        } else {
            viewPager.setScrollable(false);
        }
        startAutoPlay();
        this.setTouchEventListener(new TouchEventListener() {
            @Override
            public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
                if (isAutoPlay) {
                    int action = touchEvent.getAction();
                    if (action == PRIMARY_POINT_UP || action == CANCEL || action == NONE) {
                        startAutoPlay();
                    } else if (action == PRIMARY_POINT_DOWN) {
                        stopAutoPlay();
                    }
                }
                return true;
            }
        });
    }

    /**
     * 开始自动播放
     */
    public void startAutoPlay() {
        handler.removeCallbacks(task);
        handler.postDelayed(task, delayTime);
    }

    /**
     * 停止自动播放
     */
    public void stopAutoPlay() {
        System.out.println("------- stopAutoPlay");
        handler.removeCallbacks(task);
    }

    private final Runnable task = new Runnable() {
        @Override
        public void run() {
            if (count > 1 && isAutoPlay) {
                currentItem++;
                currentItem = currentItem % (count);
                viewPager.setCurrentPage(currentItem, true);
                handler.postDelayed(task, delayTime);
            }
        }
    };


    /**
     * 页面滑动适配器
     *
     * @author name
     * @since 2021-03-20
     */
    private class BannerPagerAdapter extends PageSliderProvider {
        @Override
        public int getCount() {
            return mDatas.size();
        }

        @Override
        public Object createPageInContainer(ComponentContainer container, int position) {
            if (creator == null) {
                throw new RuntimeException("[Banner] --> The layout is not specified,please set holder");
            }
            Component component = null;
            try {
                component = creator.createView(container.getContext(), position,
                        mDatas.get(position));
            } catch (NotExistException e) {
                Log.e("Banner", e.getMessage());
            } catch (WrongTypeException e) {
                Log.e("Banner", e.getMessage());
            } catch (IOException e) {
                Log.e("Banner", e.getMessage());
            }
            container.addComponent(component);

            if (listener != null) {
                component.setClickedListener(new ClickedListener() {
                    @Override
                    public void onClick(Component component) {
                        listener.onBannerClick(mDatas, position);
                    }
                });
            }
            return component;
        }

        @Override
        public void destroyPageFromContainer(ComponentContainer container, int i, Object object) {
            container.removeComponent((Component) object);
        }

        @Override
        public boolean isPageMatchToObject(Component component, Object oc) {
            return component == oc;
        }
    }

    @Override
    public void onPageSlideStateChanged(int state) {
        Log.e("onPageSlideStateChanged", state + "============state===");
        if (mOnPageChangeListener != null) {
            mOnPageChangeListener.onPageSlideStateChanged(state);
        }
        if (!isLoop) {
            return;
        }
        switch (state) {
            case 0: // No operation
                 viewPager.setCurrentPage(currentItem, false);
                break;
            case 1: // start Sliding
                break;
            default: // end Sliding
                Log.e("Banner", "case default");
        }
    }

    /**
     * 滑动监听器
     *
     * @param position             位置
     * @param positionOffset
     * @param positionOffsetPixels
     */
    @Override
    public void onPageSliding(int position, float positionOffset, int positionOffsetPixels) {
        Log.e("onPageSliding", position + "============position==="
                + positionOffset + "======positionOffset======" + positionOffsetPixels + "======positionOffsetPixels==");
        if (mOnPageChangeListener != null) {
            mOnPageChangeListener.onPageSliding(position, positionOffset, positionOffsetPixels);
        }
    }

    /**
     * 页面选择监听器
     *
     * @param position 位置
     */
    @Override
    public void onPageChosen(int position) {
        Log.e("onPageChosen", "======position======" + position);
        currentItem = position;
        if (mOnPageChangeListener != null) {
            mOnPageChangeListener.onPageChosen(position);
        }
        if (bannerStyle == BannerConfig.CIRCLE_INDICATOR
                || bannerStyle == BannerConfig.CIRCLE_INDICATOR_TITLE
                || bannerStyle == BannerConfig.CIRCLE_INDICATOR_TITLE_INSIDE
                || bannerStyle == BannerConfig.CUSTOM_INDICATOR) {
        }
        if (position == 0) {
            position = count;
        }
        if (position > count) {
            position = 1;
        }
    }

    /**
     * 页面改变监听器
     *
     * @param onPageChangeListener
     * @return Banner
     */
    // 选择监听器
    public Banner setOnPageChangeListener(PageSlider.PageChangedListener onPageChangeListener) {
        mOnPageChangeListener = onPageChangeListener;
        return this;
    }

    /**
     * Banner点击监听器
     *
     * @param listener
     * @return Banner
     */
    public Banner setOnBannerClickListener(OnBannerClickListener listener) {
        this.listener = listener;
        return this;
    }
}
